#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
 #include <sys/wait.h>
#include "ProcessPool.chh"

#define NUM 5//任务进程个数

int number = 1;//管道编号
class channel
{
public:
    channel(int fd, pid_t id)
    :ctrlfd(fd)
    ,workerid(id)
    {
        name = "channle-" + std::to_string(number++);
    }
    
public:
    int ctrlfd;
    pid_t workerid;
    std::string name;
};

void work()
{
    int cnt = 0;
    while(1)
    {
        int code = 0;
        ssize_t n = read(0, &code, sizeof(code));
        if(n == 0)
        {//主进程写端退出，子进程也退出
            break;
        }
        else if(n > 0)
        {
            if(!init.CheckSafe(code))
                continue;
            init.RunTask(code);
        }
        else
        {
            //nothing
        }
    }
}

void CreaterChannel(std::vector<channel> *channels)
{
    std::vector<int> old;//记录主进程的读端
    for(int i = 0; i < NUM; i++)
    {
        // 1. 创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;//防止编译器报警

        //2. 创建子进程
        pid_t id = fork();
        if(id < 0)
        {
            perror("fork");
            return;
        }

        // 3. 形成单向通信
        if(id == 0)//子进程，工作进程
        {
            if(!old.empty())//将子进程继承父进程多余读端全部关闭
            {
                for(auto rfd : old)
                {
                    close(rfd);
                }
                for(auto id : old)
                {
                    std::cout << "creater quit id:" << id << " " << std::endl;
                }
            }
            close(pipefd[1]);
            dup2(pipefd[0], 0);//将读端重定向到标准输入
            work();
            exit(0);
        }

        //父进程，主进程
        close(pipefd[0]);
        channels->push_back(channel(pipefd[1], id));
        old.push_back(pipefd[1]);
    }
}

//Debug
void PrintChannel(const std::vector<channel> &channels)
{
    std::cout << channels.size() << std::endl;
    for(int i = 0; i < channels.size(); i++)
    {
        std::cout << "name:" << channels[i].name << ", 写端描述符:" << channels[i].ctrlfd 
                  <<", 工作进程id:" << channels[i].workerid << std::endl;
    }
    std::cout << "Creater success" << std::endl;
}


void SendTask(const std::vector<channel> &channels, bool flag, int num)
{
    while(true)
    {
        int pos = 0;//所选择信道所在数组位置下标
        // 1. 选择任务
        int commit = init.SelectTask();
        if(init.CheckSafe(commit))
        {
            // 2. 选择信道， 发送任务码
            channel c = channels[pos++];
            pos %= channels.size();
            write(c.ctrlfd, &commit, sizeof(commit));

            // Debug
            std::cout << "select channel: " << c.name << ", send task:" << init.CodeToName(commit) << "[" << commit << "]"
                      << ", workerid:" << c.workerid << std::endl;
        }

        //判断是否需要退出
        if(!flag)
        {
            if(--num == 0)
                break;
        }

    }
}

void ReleaseChannels(std::vector<channel> &channels)
{
    for(auto & c : channels)
    {
        close(c.ctrlfd);
        pid_t rid = waitpid(c.workerid, nullptr, 0);
        if(rid == -1)
        {
            perror("waitpid");
            return;
        }
        std::cout << "wait " << c.name << " " << c.workerid << " success" << std::endl;
    }
}

int main()
{
    std::vector<channel> channels;
    //创建管道，创建进程
    CreaterChannel(&channels);
    std::cout << "Creater end" << std::endl;
    PrintChannel(channels);

    //主进程向工作进程发送任务
    const bool g_always_loop = true;
    SendTask(channels, !g_always_loop, 10);
    
    // 回收资源: 关闭写端，子进程自动退出
    //sleep(3);
    ReleaseChannels(channels);
    return 0;
}
